﻿using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WebPartPages;
using System.Xml;
using SP_Form_Suggestion;

namespace SP_Form_Suggestion.ConfigListEventReceiver
{
    /// <summary>
    /// Listenelementereignisse
    /// </summary>
    public class ConfigListEventReceiver : SPItemEventReceiver
    {
       
        public override void ItemAdding(SPItemEventProperties properties)
        {
            SPWeb myWeb = null;
            SPList targetList, configList = null;
            string sourceListUrl, sourceFieldNameInternal, sourceWebUrl, sourceListGUIDorName, targetListName, targetFieldName = null;
            bool useAjaxProxy = false;
            try
            {
                // ItemAdding memory leak
                myWeb = properties.OpenWeb();
                if (!myWeb.UserIsWebAdmin)
                {
                    properties.Status = SPEventReceiverStatus.CancelWithError;
                    properties.ErrorMessage = "Must be WebAdmin";
                    return;
                }
                try
                {
                    sourceListUrl = properties.AfterProperties[CONST.SOURCE_LIST_URL] as string;
                    sourceFieldNameInternal = properties.AfterProperties[CONST.SOURCE_FIELD_NAME_INTERNAL] as string;
                    sourceWebUrl = String.Empty;
                    sourceListGUIDorName = String.Empty;

                    targetListName = properties.AfterProperties[CONST.TARGET_LIST_NAME] as string;
                    targetFieldName = properties.AfterProperties[CONST.TARGET_FIELD_NAME] as string;

                    useAjaxProxy = Boolean.Parse(properties.AfterProperties[CONST.USE_AJAX_PROXY] as string);

                }
                catch (Exception ex)
                {
                    properties.Status = SPEventReceiverStatus.CancelWithError;
                    return;
                }
                // validate
                try
                {
                    try
                    {
                        targetList = myWeb.Lists[new Guid(targetListName)];
                    }
                    catch (Exception ex)
                    {
                        targetList = myWeb.Lists[targetListName];
                    }
                    if (!targetList.Fields.ContainsField(targetFieldName))
                        throw new Exception();
                    if (!validateSource(sourceListUrl, ref sourceFieldNameInternal, ref sourceListGUIDorName, ref sourceWebUrl))
                        throw new Exception();
                }
                catch (Exception ex)
                {
                    targetList = null; properties.Status = SPEventReceiverStatus.CancelWithError;
                    properties.ErrorMessage = "Validation failed.";
                    return;
                }


                properties.AfterProperties[CONST.TARGET_LIST_GUID] = targetList.ID.ToString();
                // Display name
                targetFieldName = (targetList.Fields.GetField(targetFieldName)).Title;
                properties.AfterProperties[CONST.TARGET_FIELD_NAME] = targetFieldName;
                // List name
                targetListName = targetList.Title;
                properties.AfterProperties[CONST.TARGET_LIST_NAME] = targetListName;

                properties.AfterProperties[CONST.SOURCE_WEB_URL] = sourceWebUrl;
                properties.AfterProperties[CONST.SOURCE_LIST_GUID] = sourceListGUIDorName;
                properties.AfterProperties[CONST.SOURCE_FIELD_NAME_INTERNAL] = sourceFieldNameInternal;

                // Find all entries by GUID
                //configList = properties.List;
                configList = myWeb.Lists[properties.ListId];
                SPQuery query = new SPQuery();
                query.Query = "<Where><Eq><FieldRef Name='" + CONST.TARGET_LIST_GUID + "'/>" +
                            "<Value Type='Text'>" + targetList.ID.ToString() + "</Value></Eq></Where>";

                SPListItemCollection collListItems = configList.GetItems(query);
                int itemsCount = collListItems.Count + 1;

                string[] targetFieldNameArr = new string[itemsCount];
                string[] sourceFieldNameArr = new string[itemsCount];
                string[] sourceWebUrlArr = new string[itemsCount];
                string[] sourceListGUIDArr = new string[itemsCount];
                bool[] useAjaxProxyArr = new bool[itemsCount];
                for (int i = 0, j = 0; i < collListItems.Count; i++)
                {
                    SPListItem it = collListItems[i];
                    if (!it.ID.Equals(properties.ListItemId))
                    {
                        targetFieldNameArr[j] = it[CONST.TARGET_FIELD_NAME] as string;
                        sourceFieldNameArr[j] = it[CONST.SOURCE_FIELD_NAME_INTERNAL] as string;
                        sourceWebUrlArr[j] = it[CONST.SOURCE_WEB_URL] as string;
                        sourceListGUIDArr[j] = it[CONST.SOURCE_LIST_GUID] as string;

                        if (null == (it[CONST.USE_AJAX_PROXY]))
                            useAjaxProxyArr[j] = false;
                        else
                            useAjaxProxyArr[j] = Boolean.Parse(it[CONST.USE_AJAX_PROXY].ToString() as string);
                        j++;
                    }
                }
                // New Item at the end
                itemsCount--;
                targetFieldNameArr[itemsCount] = targetFieldName;
                sourceFieldNameArr[itemsCount] = sourceFieldNameInternal;
                sourceWebUrlArr[itemsCount] = sourceWebUrl;
                sourceListGUIDArr[itemsCount] = sourceListGUIDorName;
                useAjaxProxyArr[itemsCount] = useAjaxProxy;

                createWebPart(configList, targetList, targetFieldNameArr, sourceFieldNameArr, sourceWebUrlArr, sourceListGUIDArr, "EDIT", useAjaxProxyArr);
                createWebPart(configList, targetList, targetFieldNameArr, sourceFieldNameArr, sourceWebUrlArr, sourceListGUIDArr, "NEW", useAjaxProxyArr);


         
            }
            finally
            {
                if (null != myWeb)
                    myWeb.Dispose();
            }
        }

        public override void ItemUpdating(SPItemEventProperties properties)
        {

            properties.Status = SPEventReceiverStatus.CancelWithError;
            properties.ErrorMessage = "Currently not supported. Delete and create the item again.";

        }

        public override void ItemDeleting(SPItemEventProperties properties)
        {
            if (!properties.Web.UserIsWebAdmin)
            {
                properties.Status = SPEventReceiverStatus.CancelWithError;
                properties.ErrorMessage = "Must be WebAdmin";
                return;
            }
            SPItem it = properties.ListItem;
            SPList targetList =null;
        
      
            try{
                targetList = properties.Web.Lists[new Guid(it[CONST.TARGET_LIST_GUID] as string)];
            }
            catch(Exception ex){ targetList = null;}

            if (null != targetList)
            {
                SPWeb web = targetList.ParentWeb;

                SPFile[] arr = new SPFile[2];
                arr[0] = web.GetFile(targetList.DefaultEditFormUrl);
                arr[1] = web.GetFile(targetList.DefaultNewFormUrl);
                foreach (SPFile file in arr)
                {

                    using (SPLimitedWebPartManager manager = file.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
                    {

                        for (int i = 0; i < manager.WebParts.Count; i++)
                        {
                            System.Web.UI.WebControls.WebParts.WebPart part = manager.WebParts[i];
                            if (part is ContentEditorWebPart && part.Title.Equals(CONST.WEBPARTNAME))
                            {
                                manager.DeleteWebPart(part);

                            }
                        }
                       
                    }
                }

            }
            // check if other entries exist so we have to re built it.
            SPList configList = properties.List;
            SPQuery query = new SPQuery();
            query.Query = "<Where><Eq><FieldRef Name='" + CONST.TARGET_LIST_GUID + "'/>" +
                        "<Value Type='Text'>" + it[CONST.TARGET_LIST_GUID]+ "</Value></Eq></Where>";
            SPListItemCollection collListItems = configList.GetItems(query);
            if (collListItems.Count > 1)
            {
                string[] targetFieldNameArr = new string[collListItems.Count -1];
                string[] sourceFieldNameArr = new string[collListItems.Count -1];
                string[] sourceWebUrlArr = new string[collListItems.Count -1];
                string[] sourceListGUIDArr = new string[collListItems.Count -1];
                bool[] useAjaxProxyArr = new bool[collListItems.Count - 1];
                for (int i = 0,j= 0; i < collListItems.Count; i++)
                {
                    
                    SPListItem item = collListItems[i];
                    if (!item.ID.Equals(properties.ListItemId))
                    {
                        targetFieldNameArr[j] = item[CONST.TARGET_FIELD_NAME] as string;
                        sourceFieldNameArr[j] = item[CONST.SOURCE_FIELD_NAME_INTERNAL] as string;
                        sourceWebUrlArr[j] = item[CONST.SOURCE_WEB_URL] as string;
                        sourceListGUIDArr[j] = item[CONST.SOURCE_LIST_GUID] as string;
                        if (null == (item[CONST.USE_AJAX_PROXY]))
                            useAjaxProxyArr[j] = false;
                        else
                            useAjaxProxyArr[j] = Boolean.Parse(item[CONST.USE_AJAX_PROXY].ToString() as string);
                        j++;
                    }
                }
               
                createWebPart(configList, targetList, targetFieldNameArr, sourceFieldNameArr, sourceWebUrlArr, sourceListGUIDArr, "EDIT",useAjaxProxyArr);
                createWebPart(configList, targetList, targetFieldNameArr, sourceFieldNameArr, sourceWebUrlArr, sourceListGUIDArr, "NEW",useAjaxProxyArr);
            }
   
        }

        /// <summary>
        /// Can't access the list directly, extract infos from url
        /// </summary>
        /// <param name="s">List Url e.g.: http://servername/subweb/webweb/Lists/Listname/stuff</param>
        /// <returns>string[] arr, arr[0] : Listname; arr[1] = webUrl</returns>
        private string[] getListNameAndWebUrl(string s)
        {
            string[] arr = new string[]{String.Empty,String.Empty};
            string SEARCH = "/Lists/";
            if (!s.Contains(SEARCH))
                return arr;
            int listIndex = s.LastIndexOf(SEARCH);
            // Web url
            arr[1] = s.Remove(listIndex);
            string preListName = s.Remove(0, listIndex + SEARCH.Length);
            if (preListName.Contains("/"))
                arr[0] = preListName.Remove(preListName.IndexOf('/'));
            else
                arr[0] = preListName;

            return arr;
            

        }
        private bool validateSource(string sourceListUrl, ref string sourceFieldNameInternal, ref string sourceListGUIDorName, ref string sourceWebUrl)
        {
            
   
            bool valid = false;
            SPSite site = null;
            SPWeb sourceListWeb = null;
            // Search source list
            try
            {
                SPList sourceList = GetListFromUrl(sourceListUrl, out site, out sourceListWeb);
                if (sourceList != null)
                {
                    if (!sourceList.Fields.ContainsField(sourceFieldNameInternal))
                        return false;
                    SPField sourceField = sourceList.Fields.GetField(sourceFieldNameInternal);
                    sourceFieldNameInternal = sourceField.InternalName;
                    sourceListGUIDorName = sourceList.ID.ToString();
                    sourceWebUrl = sourceListWeb.Url;

                    valid = true;
                }
                else
                {
                    string[] data = getListNameAndWebUrl(sourceListUrl);
                    if (String.IsNullOrEmpty(data[0]) || String.IsNullOrEmpty(data[1]))
                        return false;
                    sourceWebUrl = data[1];
                    sourceListGUIDorName = data[0];

                    valid = true;
                }
            }
            finally
            {
                if (null != sourceListWeb)
                    sourceListWeb.Dispose();
                if (null != site)
                    site.Dispose();
            }
       
            return valid;
        }
        private SPList GetListFromUrl(string url,out SPSite listSite,out SPWeb listWeb)
        {
            
            SPList list = null;
            SPWeb web = null;
            SPSite site = null;

            try
            {
                site = new SPSite(url);
                web = site.OpenWeb();
                try
                {
                    list = web.GetList(url);
                }
                catch (Exception ex)
                {
                    try
                    {
                        list = web.GetListFromUrl(url);
                    }
                    catch (Exception ex2)
                    {
                        list = null;
                    }
                }
            }
            catch (Exception ex)
            {
                list = null;
            }
            finally
            {
                listWeb = web;
                listSite = site;
            }
            return list;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="targetList"></param>
        /// <param name="targetField"></param>
        /// <param name="sourceField"></param>
        /// <param name="sourceList"></param>
        /// <param name="form">EditForm: "EDIT", NewForm: "any other string" </param>
        private void createWebPart(SPList configList,SPList targetList,
            string[] targetFieldNameArr,
            string[] sourceFieldNameArr,
            string[] sourceWebUrlArr,
            string[] sourceListGUIDArr,
            string form,
            bool[] useAjaxProxyArr)
        {

                SPWeb web = targetList.ParentWeb;
                SPFile file;
          
        
                if (form.Equals("EDIT"))
                    file = web.GetFile(targetList.DefaultEditFormUrl);
                else
                    file = web.GetFile(targetList.DefaultNewFormUrl);

                using (SPLimitedWebPartManager manager = file.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
                 {

                    ContentEditorWebPart cewp = null;
                    try
                    {
                        foreach (Microsoft.SharePoint.WebPartPages.WebPart part in manager.WebParts)
                        {

                            if (part is ContentEditorWebPart && part.Title.Equals(CONST.WEBPARTNAME))
                            {

                                cewp = part as ContentEditorWebPart;
                                break;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        cewp = null;
                    }



                    // New WebPart
                    if (null == cewp)
                    {
                        cewp = new ContentEditorWebPart();
                  
                        // Settings
                       
                        cewp.Title = CONST.WEBPARTNAME;
                        cewp.Hidden = true;
                        cewp.ZoneID = "Main";
                        
                        manager.AddWebPart(cewp, "Main",manager.WebParts.Count+1);
                    }
                  
               


                    // Jquery Ref
                    string jquery, jquery_ui, jquery_ui_css = null;
                    SPWeb configWeb = configList.ParentWeb;

                    jquery = configWeb.GetProperty(CONST.PROPERTY_BAG_JQUERY_URL) as string;
                    jquery_ui = configWeb.GetProperty(CONST.PROPERTY_BAG_JQUERY_UI_URL) as string;
                    jquery_ui_css = configWeb.GetProperty(CONST.PROPERTY_BAG_JQUERY_UI_CSS_URL) as string;

                    // Content
                    XmlDocument xmlDoc = new XmlDocument();
                    XmlElement xmlElement = xmlDoc.CreateElement("MyElement");
                    xmlElement.InnerText =  ScriptManager.createScript(true, CONST.PROXY_URL, targetFieldNameArr,
                                                                                 sourceWebUrlArr,
                                                                                 sourceFieldNameArr,
                                                                                 sourceListGUIDArr,
                                                                                      jquery,
                                                                                      jquery_ui,
                                                                                      jquery_ui_css,
                                                                                      useAjaxProxyArr);
                   
                    cewp.Content = xmlElement;
                    // update WebPart
                    manager.SaveChanges(cewp);

                
                }
           
            
        }
    }
}
